package com.koron.order.perambulate.bean.excel;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.koron.bean.base.Response;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.business.datadict.utils.DataDictTool;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.order.overhaul.bean.dto.Equipment;
import com.koron.order.perambulate.bean.vo.MonitorChangeVo;
import com.koron.order.perambulate.service.LinePerambulateService;
import com.koron.order.risk.base.excel.ExcelError;
import com.koron.order.risk.base.mapper.LineEquipmentMapper;
import com.koron.order.risk.feign.LineEquipmentFeign;
import com.koron.order.risk.feign.dto.EquipmentParams;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName: MonitorListener
 * @Description:
 * @Date: 2023/2/2
 * @Author: 李一辰
 * @Version: 1.0
 **/
@Slf4j
public class MonitorListener  extends AnalysisEventListener<MonitorChangeExcel>  {


    private LinePerambulateService linePerambulateService;
    private LineEquipmentFeign equipmentFeign;

    private String peramId;

    private LinePerambulateConvertor linePerambulateConvertor;

    public MonitorListener(LinePerambulateService linePerambulateService,String peramId) {
        this.linePerambulateService = linePerambulateService;
        this.peramId = peramId;
    }

    public EamUser getCurr(){return ThreadLocalContext.get();}
    // 每隔100条，然后清理list ，方便内存回收
    private static final int BATCH_COUNT = 100;
    // 要保存的数据
    private final List<MonitorChangeVo> LineRiskVOList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    // 设备缓存
    private final Equipment rootEquipment = allLineEquipment();
    // 错误数据信息
    private final List<MonitorChangeExcel> errorRisk = new ArrayList<>();
    // 错误备注信息
    private final Map<Integer, ExcelError> excelErrors = new HashMap<>();

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    @Override
    public void invoke(MonitorChangeExcel data, AnalysisContext context) {
        MonitorChangeVo monitorChangeVo = fillData(data);
        if (monitorChangeVo == null) {
            return;
        }
        LineRiskVOList.add(monitorChangeVo);
        if (LineRiskVOList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            LineRiskVOList.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        log.info("所有数据解析完成！");
    }
    private void saveData() {
        beforeSave();
        ADOConnection.runTask(getCurrDs(), linePerambulateService, "BatchInsert1", Integer.class, LineRiskVOList);
        log.info("存储数据库成功！");
    }

    private void beforeSave() {
        List<String> ids = LineRiskVOList.stream().map(MonitorChangeVo::getTowerNumber).collect(Collectors.toList());

        Response<List<EquipmentParams>> batchBaseParams = equipmentFeign.getBatchBaseParams(ids);
        if (CollUtil.isEmpty(batchBaseParams.getData())) {
            return;
        }

        List<EquipmentParams> data = batchBaseParams.getData();
        Map<String, String> deptMap = data.stream()
                .filter(e -> Objects.equals("管理部门", e))
                .collect(Collectors.toMap(EquipmentParams::getEquipmentId, EquipmentParams::getParamValue, (o1, o2) -> o1));

        for (MonitorChangeVo monitorChangeVo : LineRiskVOList) {
            monitorChangeVo.setBelongDept(deptMap.get(monitorChangeVo.getTowerNumber()));
        }

    }

    /**
     * 填充数据字段
     */
    private MonitorChangeVo fillData(MonitorChangeExcel data) {
        if (data == null) {
            return null;
        }
        //线路
        MonitorChangeVo monitorChangeVo = ExceltoVO(data);
        monitorChangeVo.setPeramId(peramId);
        monitorChangeVo.setCreateName(getCurr().getCreateByName());
        monitorChangeVo.setCreateTime(new Date());
        monitorChangeVo.setRemark(data.getRemark());
        String lineName = monitorChangeVo.getEquipmentName();
        if(lineName == null){
            fillError(data,0,"线路名称不能为空");
        }
        Equipment line = getLineByName(lineName);
        if (line == null) {
            fillError(data, 0, "线路：" + monitorChangeVo.getEquipmentName() + "不存在");
            return null;
        }  else {
            monitorChangeVo.setId(CodeTools.getCode32());

        }

        // 塔段
        if (StrUtil.isEmpty(monitorChangeVo.getTowerNumber())) {
            fillError(data, 4, "杆塔不能为空");
            return null;
        }
        Equipment tower = getTowerByNamesAndChildren(line.getName(), monitorChangeVo.getTowerNumber(), line.getChildren());
        if (tower == null) {
            fillError(data, 4, "杆塔：" + data.getTowerNumber() + "不存在");
            return null;
        }  else {
            monitorChangeVo.setTowerNumber(data.getTowerNumber());
            String id = tower.getId();
            String typeId = tower.getTypeId();
            String deptName = ADOConnection.runTask(getCurrDs(), linePerambulateService, "getDeptByIdAndParamId", String.class, id, typeId);
            monitorChangeVo.setBelongDept(deptName);
        }
        //校验风险等级
        String riskLevel = data.getRiskLevel();
        if(riskLevel==null){
            fillError(data,1,"风险等级不能为空");
            return null;
        }
        log.info(riskLevel);
        Map<String, String> dataDictByCode = DataDictTool.getDataDictByCode("transmissionRiskControl", "risk_level");
        Stream<String> array = dataDictByCode.keySet().stream();
        boolean b = array.anyMatch(i -> i.equals(riskLevel));
        if(!b){
            fillError(data,1,"风险等级不存在");
            return null;
        }
        //数字校验
        boolean number1 = NumberUtil.isNumber(data.getDistanceTower());
        boolean number2 = NumberUtil.isNumber(data.getLongitude());
        boolean number3 = NumberUtil.isNumber(data.getLatitude());
        if(!number1){
            fillError(data,4,"最近杆塔距离输入非数值型，不是整数或小数");
            return null;
        }
        monitorChangeVo.setDistanceTower(data.getDistanceTower());
        if(!number2){
            fillError(data,7,"经度输入非数值型，不是整数或小数");
            return null;
        }
        monitorChangeVo.setLongitude(data.getLongitude());
        if(!number3){
            fillError(data,8,"纬度输入非数值型，不是整数或小数");
            return null;
        }
        monitorChangeVo.setLatitude(data.getLatitude());

        return monitorChangeVo;
    }

    private void fillError(MonitorChangeExcel data, int collIndex, String tip) {
        errorRisk.add(data);
        ExcelError excelError = new ExcelError(errorRisk.size(), collIndex, tip);
        excelErrors.put(errorRisk.size()+1, excelError);
        log.error(tip);
    }


    private Equipment allLineEquipment() {
        // 1. 查询根设备
        Map<String, String> config = ConfigInfoTool.getConfigByCode("equipment", "line_root_device");
        String id = config.get("id");
        try (SessionFactory factory = new SessionFactory()) {
            factory.setDbEnv(getCurrDs());
            LineEquipmentMapper mapper = factory.getMapper(LineEquipmentMapper.class);
            Equipment root = mapper.getById(id);
            List<Equipment> equipmentList = mapper.selectSimpleLineEquipment(root.getLevelPath(), root.getLevel() + 3);
            // 线路设备
            Map<String, Equipment> lineEquipmentMap = new HashMap<>();
            for (Equipment equipment : equipmentList) {
                // 本身equipmentList就是有序的
                // 添加线路设备
                String parentId = equipment.getParentId();
                if (parentId.equals(root.getId())) {
                    if (root.getChildren() == null) {
                        root.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = root.getChildren();
                        children.add(equipment);
                    }
                    lineEquipmentMap.put(equipment.getId(), equipment);
                }

                // 添加杆塔
                if (lineEquipmentMap.containsKey(parentId)) {
                    Equipment parent = lineEquipmentMap.get(parentId);
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = parent.getChildren();
                        children.add(equipment);
                    }
                }
            }
            return root;
        }
    }

    private Equipment getLineByName(String name) {
        List<Equipment> children = rootEquipment.getChildren();
        List<Equipment> lines = children.stream().filter(e -> name.equals(e.getName())).collect(Collectors.toList());
        if (lines.isEmpty()) {
            return null;
        } else {
            return lines.get(0);
        }
    }
        private Equipment getTowerByNamesAndChildren(String parentName, String name, List<Equipment> children) {
            if(name.contains("塔")){
                List<Equipment> tower1 = children.stream().filter(i -> i.getName().equals(parentName + name )).collect(Collectors.toList());
                if (CollUtil.isEmpty(tower1)) {
                    return null;
                }
                return tower1.get(0);
            }
            else{
                List<Equipment> tower2 = children.stream().filter(i -> i.getName().equals(parentName + name + "塔")).collect(Collectors.toList());
                if (CollUtil.isEmpty(tower2)) {
                    return null;
                }
                return tower2.get(0);
            }
        }


    public List<MonitorChangeExcel> getErrorRisk() {
        return errorRisk;
    }

    public List<ExcelError> getExcelErrors() {
        return new ArrayList<>(excelErrors.values());
    }

     public MonitorChangeVo ExceltoVO(MonitorChangeExcel monitorChangeExcel){
         if(monitorChangeExcel == null){
             return new MonitorChangeVo();
         }
          MonitorChangeVo monitorChangeVo = new MonitorChangeVo();
        monitorChangeVo.setArea(monitorChangeExcel.getArea());
        monitorChangeVo.setDistanceTower(monitorChangeExcel.getDistanceTower());
        monitorChangeVo.setDistaneLine(monitorChangeExcel.getDistanceLine());
        monitorChangeVo.setEquipmentName(monitorChangeExcel.getEquipmentName());
        monitorChangeVo.setLatitude(monitorChangeExcel.getLatitude());
        monitorChangeVo.setLongitude(monitorChangeExcel.getLongitude());
        monitorChangeVo.setPostKeyword(monitorChangeExcel.getPostKeyword());
        monitorChangeVo.setPreKeyword(monitorChangeExcel.getPreKeyword());
        monitorChangeVo.setRemark(monitorChangeExcel.getRemark());
        monitorChangeVo.setTowerNumber(monitorChangeExcel.getTowerNumber());
        monitorChangeVo.setRiskLevel(monitorChangeExcel.getRiskLevel());
        return monitorChangeVo;
     }
}
